package com.fzq.service.impl;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class DockerLibreOfficeService {

    private static final Logger logger = LoggerFactory.getLogger(DockerLibreOfficeService.class);

    @Value("${docker.container.name:libreoffice-server}")
    private String containerName;

    @Value("${docker.workspace.path:C:/docker-workspace}")
    private String dockerWorkspacePath;

    @Value("${docker.container.workspace:/workspace}")
    private String containerWorkspacePath;

    @Value("${docker.timeout.seconds:120}")
    private long timeoutSeconds;

    // 扩展的转换格式映射
    private static final String[][] SUPPORTED_CONVERSIONS = {
            // ========== 文档转PDF ==========
            {"doc", "pdf"}, {"docx", "pdf"}, {"xls", "pdf"}, {"xlsx", "pdf"},
            {"ppt", "pdf"}, {"pptx", "pdf"}, {"odt", "pdf"}, {"ods", "pdf"},
            {"odp", "pdf"}, {"rtf", "pdf"}, {"txt", "pdf"},

            // ========== 文档转HTML ==========
            {"doc", "html"}, {"docx", "html"}, {"xls", "html"}, {"xlsx", "html"},
            {"odt", "html"}, {"ods", "html"}, {"ppt", "html"}, {"pptx", "html"},

            // ========== 文档转文本 ==========
            {"doc", "txt"}, {"docx", "txt"}, {"odt", "txt"}, {"rtf", "txt"}, {"pdf", "txt"},

            // ========== 图片转PDF ==========
            {"jpg", "pdf"}, {"jpeg", "pdf"}, {"png", "pdf"}, {"gif", "pdf"},
            {"bmp", "pdf"}, {"tiff", "pdf"}, {"svg", "pdf"},

            // ========== PDF相关转换 ==========  不支持
//            {"pdf", "html"}, {"pdf", "txt"}, {"pdf", "odt"}, {"pdf", "docx"},

            // ========== Office格式互转 ==========
            {"doc", "docx"}, {"docx", "doc"}, {"xls", "xlsx"}, {"xlsx", "xls"},
            {"ppt", "pptx"}, {"pptx", "ppt"},

            // ========== 开放文档格式 ==========
            {"doc", "odt"}, {"docx", "odt"}, {"xls", "ods"}, {"xlsx", "ods"},
            {"ppt", "odp"}, {"pptx", "odp"},

            // ========== 其他转换 ==========
            {"html", "pdf"}, {"html", "docx"}, {"xml", "pdf"}, {"csv", "xlsx"}
    };

    /**
     * 检查Docker容器是否可用
     */
    public boolean checkDockerContainer() {
        try {
            Process process = Runtime.getRuntime().exec(
                    new String[]{"docker", "ps", "--filter", "name=" + containerName, "--format", "{{.Names}}"}
            );

            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String output = reader.readLine();
            int exitCode = process.waitFor(10, TimeUnit.SECONDS) ? process.exitValue() : -1;

            boolean available = exitCode == 0 && output != null && output.trim().equals(containerName);
            logger.info("Docker容器检查: {}", available ? "可用" : "不可用");
            return available;

        } catch (Exception e) {
            logger.error("检查Docker容器失败", e);
            return false;
        }
    }

    /**
     * 检查LibreOffice是否可用
     */
    public boolean checkLibreOffice() {
        try {
            Process process = Runtime.getRuntime().exec(
                    new String[]{"docker", "exec", containerName, "libreoffice", "--version"}
            );

            int exitCode = process.waitFor(30, TimeUnit.SECONDS) ? process.exitValue() : -1;
            boolean available = exitCode == 0;
            logger.info("LibreOffice检查: {}", available ? "可用" : "不可用");
            return available;

        } catch (Exception e) {
            logger.error("检查LibreOffice失败", e);
            return false;
        }
    }

    /**
     * 检查是否支持指定的格式转换
     */
    public boolean isConversionSupported(String inputFormat, String outputFormat) {
        for (String[] conversion : SUPPORTED_CONVERSIONS) {
            if (conversion[0].equalsIgnoreCase(inputFormat) &&
                    conversion[1].equalsIgnoreCase(outputFormat)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取支持的所有转换格式
     */
    public String[][] getSupportedConversions() {
        return SUPPORTED_CONVERSIONS;
    }

    /**
     * 执行文档转换
     */
    public File convertDocument(MultipartFile file, String targetFormat) throws IOException, InterruptedException {
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null) {
            throw new IllegalArgumentException("文件名不能为空");
        }

        String inputExtension = getFileExtension(originalFilename).toLowerCase();

        // 验证转换是否支持
        if (!isConversionSupported(inputExtension, targetFormat)) {
            throw new IllegalArgumentException("不支持从 " + inputExtension + " 转换为 " + targetFormat);
        }

        // 创建工作目录
        String jobId = UUID.randomUUID().toString();
        File jobDir = new File(dockerWorkspacePath, jobId);
        if (!jobDir.exists() && !jobDir.mkdirs()) {
            throw new IOException("无法创建工作目录: " + jobDir.getAbsolutePath());
        }

        // 准备文件
        String inputFilename = "input." + inputExtension;
        File inputFile = new File(jobDir, inputFilename);
        File outputFile = new File(jobDir, "output." + targetFormat);

        try {
            // 保存上传的文件
            Files.copy(file.getInputStream(), inputFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

            // 将文件复制到Docker容器
            String containerInputPath = containerWorkspacePath + "/" + jobId + "/" + inputFilename;
            copyFileToContainer(inputFile.getAbsolutePath(), containerInputPath);

            // 在容器内执行转换
            String containerOutputDir = containerWorkspacePath + "/" + jobId;
            executeConversion(containerInputPath, targetFormat, containerOutputDir);

            // 从容器复制结果文件
            String containerOutputPath = containerOutputDir + "/input." + targetFormat;
            copyFileFromContainer(containerOutputPath, outputFile.getAbsolutePath());

            if (!outputFile.exists()) {
                throw new IOException("转换后的文件未生成");
            }

            logger.info("文档转换成功: {} -> {}", originalFilename, outputFile.getName());
            return outputFile;

        } catch (Exception e) {
            // 清理工作目录
            cleanupDirectory(jobDir);
            throw e;
        }
    }

    /**
     * 将文件复制到Docker容器
     */
    private void copyFileToContainer(String localPath, String containerPath) throws IOException, InterruptedException {
        Process process = Runtime.getRuntime().exec(
                new String[]{"docker", "cp", localPath, containerName + ":" + containerPath}
        );

        int exitCode = process.waitFor(30, TimeUnit.SECONDS) ? process.exitValue() : -1;
        if (exitCode != 0) {
            throw new IOException("复制文件到容器失败，退出码: " + exitCode);
        }
    }

    /**
     * 从Docker容器复制文件
     */
    private void copyFileFromContainer(String containerPath, String localPath) throws IOException, InterruptedException {
        Process process = Runtime.getRuntime().exec(
                new String[]{"docker", "cp", containerName + ":" + containerPath, localPath}
        );

        int exitCode = process.waitFor(30, TimeUnit.SECONDS) ? process.exitValue() : -1;
        if (exitCode != 0) {
            throw new IOException("从容器复制文件失败，退出码: " + exitCode);
        }
    }

    /**
     * 在容器内执行转换命令
     */
    private void executeConversion(String inputPath, String targetFormat, String outputDir)
            throws IOException, InterruptedException {

        String[] command = {
                "docker", "exec", containerName,
                "libreoffice", "--headless", "--convert-to", targetFormat,
                "--outdir", outputDir, inputPath
        };

        ProcessBuilder processBuilder = new ProcessBuilder(command);
        processBuilder.redirectErrorStream(true);

        Process process = processBuilder.start();

        // 读取输出
        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
                logger.debug("LibreOffice: {}", line);
            }
        }

        // 等待完成
        boolean finished = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
        if (!finished) {
            process.destroyForcibly();
            throw new RuntimeException("转换超时，超过 " + timeoutSeconds + " 秒");
        }

        int exitCode = process.exitValue();
        if (exitCode != 0) {
            throw new RuntimeException("转换失败，退出码: " + exitCode + "\n输出: " + output);
        }

        logger.info("转换命令执行成功: {}", String.join(" ", command));
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String filename) {
        int lastDotIndex = filename.lastIndexOf(".");
        if (lastDotIndex > 0) {
            return filename.substring(lastDotIndex + 1);
        }
        return "";
    }

    /**
     * 清理目录
     */
    private void cleanupDirectory(File directory) {
        if (directory.exists()) {
            try {
                Files.walk(directory.toPath())
                        .sorted((a, b) -> -a.compareTo(b))
                        .forEach(path -> {
                            try {
                                Files.deleteIfExists(path);
                            } catch (IOException e) {
                                logger.warn("无法删除文件: {}", path, e);
                            }
                        });
            } catch (IOException e) {
                logger.warn("清理目录失败: {}", directory.getAbsolutePath(), e);
            }
        }
    }

    /**
     * 获取服务状态信息
     */
    public Object getServiceStatus() {
        boolean dockerStatus = checkDockerContainer();
        boolean officeStatus = dockerStatus && checkLibreOffice();

        return new Object() {
            public final boolean dockerAvailable = dockerStatus;
            public final boolean libreOfficeAvailable = officeStatus;
            public final String serviceStatus = libreOfficeAvailable ? "正常运行" :
                    dockerAvailable ? "LibreOffice不可用" : "Docker容器不可用";
            public final String workspacePath = dockerWorkspacePath;
            public final String containerName = DockerLibreOfficeService.this.containerName;
        };
    }
}
